home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 October / CHIP Turkiye Ekim 2000.iso / prog / naps / 04 / setup.exe / Gnucleus / ViewSearch.cpp < prev    next >
C/C++ Source or Header  |  2000-07-15  |  21KB  |  776 lines

  1. /********************************************************************************
  2.  
  3.     Gnucleus - A node application for the Gnutella network
  4.     Copyright (C) 2000 John Marshall
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     For support, questions, comments, etc...
  20.     E-Mail: 
  21.         swabby@c0re.net
  22.     
  23.     Address:
  24.         21 Cadogan Way
  25.         Nashua, NH, USA 03062
  26.  
  27. ********************************************************************************/
  28.  
  29. // ViewSearch.cpp : implementation file
  30. //
  31.  
  32. #include "stdafx.h"
  33. #include "Gnucleus.h"
  34. #include "MainFrm.h"
  35.  
  36. #include "GnucleusDoc.h"
  37. #include "ViewTransfer.h"
  38. #include "ViewSearch.h"
  39.  
  40. #include "IPFilter.h"
  41.  
  42. #include "GnuTransfer.h"
  43. #include "GnuHash.h"
  44. #include "GnuSock.h"
  45. #include "GnuControl.h"
  46.  
  47.  
  48. #ifdef _DEBUG
  49. #define new DEBUG_NEW
  50. #undef THIS_FILE
  51. static char THIS_FILE[] = __FILE__;
  52. #endif
  53.  
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CViewSearch
  56.  
  57. IMPLEMENT_DYNCREATE(CViewSearch, CFormView)
  58.  
  59. CViewSearch::CViewSearch()
  60.     : CFormView(CViewSearch::IDD)
  61. {
  62.     //{{AFX_DATA_INIT(CViewSearch)
  63.     //}}AFX_DATA_INIT
  64.     
  65.     BytesPerSec = 0;
  66.  
  67.     row = 0;
  68.     matches = 0;
  69. }
  70.  
  71. CViewSearch::~CViewSearch()
  72. {
  73. }
  74.  
  75. void CViewSearch::DoDataExchange(CDataExchange* pDX)
  76. {
  77.     CFormView::DoDataExchange(pDX);
  78.     //{{AFX_DATA_MAP(CViewSearch)
  79.     DDX_Control(pDX, IDC_BUTTON_DOWNLOAD, m_btnDownload);
  80.     DDX_Control(pDX, IDC_STATIC_MATCHES, m_stcMatches);
  81.     DDX_Control(pDX, IDC_STATIC_SUBSEARCH, m_stcSubsearch);
  82.     DDX_Control(pDX, IDC_STATIC_EXCLUDE, m_stcExclude);
  83.     DDX_Control(pDX, IDC_LIST_RESULTS, m_lstResults);
  84.     DDX_Control(pDX, IDC_EDIT_SUBSEARCH, m_eSubsearch);
  85.     DDX_Control(pDX, IDC_EDIT_EXCLUDE, m_eExclude);
  86.     //}}AFX_DATA_MAP
  87. }
  88.  
  89.  
  90. BEGIN_MESSAGE_MAP(CViewSearch, CFormView)
  91.     //{{AFX_MSG_MAP(CViewSearch)
  92.     ON_WM_SIZE()
  93.     ON_NOTIFY(NM_DBLCLK, IDC_LIST_RESULTS, OnDblclkListResults)
  94.     ON_BN_CLICKED(IDC_BUTTON_DOWNLOAD, OnButtonDownload)
  95.     ON_NOTIFY(NM_CLICK, IDC_LIST_RESULTS, OnClickListResults)
  96.     ON_NOTIFY(NM_RCLICK, IDC_LIST_RESULTS, OnRightClickListResults)
  97.     ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST_RESULTS, OnItemclickListResults)
  98.     ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_RESULTS, OnColumnclickListResults)
  99.     ON_EN_CHANGE(IDC_EDIT_SUBSEARCH, OnChangeSubsearch)
  100.     ON_EN_CHANGE(IDC_EDIT_EXCLUDE, OnChangeExclude)
  101.     //}}AFX_MSG_MAP
  102. END_MESSAGE_MAP()
  103.  
  104. /////////////////////////////////////////////////////////////////////////////
  105. // CViewSearch diagnostics
  106.  
  107. #ifdef _DEBUG
  108. void CViewSearch::AssertValid() const
  109. {
  110.     CFormView::AssertValid();
  111. }
  112.  
  113. void CViewSearch::Dump(CDumpContext& dc) const
  114. {
  115.     CFormView::Dump(dc);
  116. }
  117. #endif //_DEBUG
  118.  
  119. /////////////////////////////////////////////////////////////////////////////
  120. // CViewSearch message handlers
  121.  
  122. void CViewSearch::OnInitialUpdate() 
  123. // Initializes all the dialog controls on the local view
  124. {
  125.     CFormView::OnInitialUpdate();
  126.     
  127.     Doc = (CGnucleusDoc *) GetDocument();
  128.     Comm = Doc->GnuComm;
  129.  
  130.     NoScroll = 0;
  131.  
  132.     // Resize the window, set up the list box
  133.     int offSet;
  134.  
  135.     if(m_lstResults.GetScrollLimit(SB_VERT))
  136.         offSet = ::GetSystemMetrics(SM_CXVSCROLL) + 3;
  137.     else
  138.         offSet = 4;
  139.  
  140.     CRect rect;
  141.     m_lstResults.GetWindowRect(&rect);
  142.  
  143.     m_lstResults.InsertColumn(0, "Name", LVCFMT_LEFT,
  144.         (rect.Width() - offSet) * 5/12, 0);
  145.     m_lstResults.InsertColumn(1, "Bytes", LVCFMT_RIGHT,
  146.         (rect.Width() - offSet) * 2/12, 1);
  147.     m_lstResults.InsertColumn(2, "Type", LVCFMT_LEFT,
  148.         (rect.Width() - offSet) * 2/12, 1);
  149.     m_lstResults.InsertColumn(3, "Node", LVCFMT_CENTER,
  150.         (rect.Width() - offSet) * 2/12, 0);    
  151.     m_lstResults.InsertColumn(4, "Speed", LVCFMT_RIGHT,
  152.         (rect.Width() - offSet) * 1/12, 0);    
  153.  
  154.     m_lstResults.SetExtendedStyle(LVS_EX_FULLROWSELECT);
  155.  
  156.     GetParentFrame()->GetClientRect(&rect);
  157.     OnSize(SIZE_RESTORED, rect.right - 4, rect.bottom - 4);
  158.  
  159.     // Create and set the image list to store file icons
  160.     m_lstResults.SetImageList(GetSharedImageList(), LVSIL_SMALL);
  161.  
  162.     // disable plain text sort with search items.
  163.     m_lstResults.EnableGenericSort(FALSE);
  164.  
  165.     // Disable button
  166.     m_btnDownload.EnableWindow(FALSE);
  167.  
  168.     // Get search value from title
  169.     CString Title;
  170.  
  171.     GetParentFrame()->GetWindowText(Title);
  172.     length = Title.GetLength() - 16;
  173.     keyword = Title.Mid(15, length);
  174.  
  175.     // Send a search query out for the keyword
  176.     CString strSpeed;
  177.     CComboBox *cbSpeed = (CComboBox *) ( (CMainFrame *) AfxGetApp()->m_pMainWnd )->GetDialogBar()->GetDlgItem(IDC_COMBO_SPEED);
  178.     cbSpeed->GetWindowText(strSpeed);
  179.  
  180.     
  181.     BytesPerSec = GetSpeedinBytes(strSpeed);
  182.  
  183.     Send_Query();
  184. }
  185.  
  186. WORD CViewSearch::GetSpeedinBytes(CString Speed)
  187. // Speeds are in *bytes*/second
  188. {
  189.     if(Speed == "")
  190.         return 0;
  191.     if(Speed == "14.4 Modem")
  192.         return 14;
  193.     if(Speed == "28.8 Modem")
  194.         return 29;
  195.     if(Speed == "56K Modem")
  196.         return 53;
  197.     if(Speed == "ISDN-56K")
  198.         return 56;
  199.     if(Speed == "ISDN-128K")
  200.         return 128;
  201.     if(Speed == "Cable")
  202.         return 384;
  203.     if(Speed == "DSL")
  204.         return 768;
  205.     if(Speed == "T1")
  206.         return 1500;
  207.     if(Speed == "T3 (or Greater)")
  208.         return 45000;
  209.     
  210.     return (WORD) atof(Speed);
  211. }
  212.  
  213.  
  214. void CViewSearch::Send_Query()
  215. // Build a query packet
  216. {
  217.     GUID Guid = GUID_NULL;
  218.     ::CoCreateGuid(&Guid);
  219.     if (Guid == GUID_NULL)
  220.     {
  221.         AfxMessageBox("Failed to create a GUID to send.");
  222.         return;
  223.     }
  224.  
  225.     myGuid = Guid;
  226.  
  227.     BYTE QueryByte[23 + 255];
  228.     packet_Query Query;
  229.     byte *pQuery = (byte *) &Query;
  230.  
  231.      Query.Header.Guid = Guid;
  232.     Query.Header.Function = 0x80;
  233.     Query.Header.Hops = 0;
  234.     Query.Header.TTL = 7;
  235.     Query.Header.Payload = flipX( makeX(length + 3) );
  236.     Query.Speed = BytesPerSec;
  237.  
  238.     for(int i = 0; i < 25; i++)
  239.         QueryByte[i] = pQuery[i];
  240.  
  241.     // Add Search
  242.     for(i = 0; i < keyword.GetLength(); i++)
  243.         QueryByte[25 + i] = keyword.GetAt(i); 
  244.  
  245.     QueryByte[25 + length] = NULL;
  246.  
  247.     // Insert GUID and broadcast the query
  248. //    Comm->m_cache[Guid] = NULL;
  249. //    Comm->HashTable.Insert(&Guid, NULL);
  250.     Comm->SendTable.Insert(&Guid, NULL);
  251.     Comm->Broadcast_Query((packet_Query *) QueryByte, 26 + length, NULL);
  252. }
  253.  
  254. // move into position one of the controls at the bottom of the search window
  255. void CViewSearch::AdjustBottomControl(CWnd *cntl, int bot)
  256. {
  257.     CRect r, par;
  258.     cntl->GetWindowRect(&r);
  259.     ScreenToClient(&r);
  260.     const int hoff = 2, height = 32;
  261.     cntl->MoveWindow(r.left, (bot - hoff - height) + (height - r.Height()) / 2, r.Width(), r.Height());
  262. }
  263.  
  264. void CViewSearch::OnSize(UINT nType, int cx, int cy) 
  265. // Adjusts dialog controls when window in resized
  266. {
  267.     // Make sure dialog controls exist
  268.     if(m_lstResults.m_hWnd != NULL)
  269.     {
  270.         int top, left, btnLeft, btnRight, btnBottom;
  271. //        int btn2Left, btn2Right; // DW - not used yet?
  272.  
  273.         RECT wndRect, 
  274.                lstRect, 
  275.                btnRect; 
  276. //               btnRect2;  // DW BTW, btnRect2 is not used for anything yet
  277.  
  278.         GetWindowRect(&wndRect);
  279.         m_lstResults.GetWindowRect(&lstRect);
  280.         m_btnDownload.GetWindowRect(&btnRect);
  281.  
  282.         top  = lstRect.top  - wndRect.top  - 2;
  283.         left = lstRect.left - wndRect.left - 2;
  284.  
  285.         btnLeft   = btnRect.left - wndRect.left - 2;
  286.         btnRight  = btnRect.right  - btnRect.left;
  287.         btnBottom = btnRect.bottom - btnRect.top;
  288.  
  289. //        btn2Left = btnRight + 8;                     // DW So, these are not valid yet
  290. //        btn2Right = btnRect2.right - btnRect2.left;
  291.  
  292.         m_lstResults.MoveWindow(left, top, cx - left - 7, cy - top - btnBottom - 17);
  293.         m_btnDownload.MoveWindow(btnLeft, cy - 8 - btnBottom, btnRight, btnBottom);
  294.  
  295.         AdjustBottomControl(&m_eSubsearch, cy);
  296.         AdjustBottomControl(&m_stcSubsearch, cy);
  297.         AdjustBottomControl(&m_stcExclude, cy);
  298.         AdjustBottomControl(&m_eExclude, cy);
  299.  
  300.         // Resize list box
  301.         int offSet;
  302.  
  303.         if(m_lstResults.GetScrollLimit(SB_VERT))
  304.             offSet = ::GetSystemMetrics(SM_CXVSCROLL) + 3;
  305.         else
  306.             offSet = 4;
  307.  
  308.         CRect rect;
  309.         m_lstResults.GetWindowRect(&rect);
  310.  
  311.         m_lstResults.SetColumnWidth(0, (rect.Width() - offSet) * 5/12);
  312.         m_lstResults.SetColumnWidth(1, (rect.Width() - offSet) * 2/12);
  313.         m_lstResults.SetColumnWidth(2, (rect.Width() - offSet) * 2/12);
  314.         m_lstResults.SetColumnWidth(3, (rect.Width() - offSet) * 2/12);
  315.         m_lstResults.SetColumnWidth(4, (rect.Width() - offSet) * 1/12);
  316.     }
  317.  
  318.     CFormView::OnSize(nType, cx, cy);
  319.     
  320. }
  321.  
  322. void CViewSearch::UpdateResults(byte *Result)
  323. {
  324.     if( ((packet_Header *) Result)->Guid != myGuid)
  325.         return;
  326.  
  327.     DWORD length  = makeD( flipX( ((packet_Header *) Result)->Payload)) + 23;
  328.     CString Node  = IPtoStr( ((packet_QueryReply *) Result)->Host );
  329.     CString Port  = WrdtoStr( ((packet_QueryReply *) Result)->Port );
  330.     CString Speed = DWrdtoStr( makeD( flipX( ((packet_QueryReply *) Result)->Speed)) );
  331.     CString File;
  332.     CString Size;
  333.     CString FileType;
  334.  
  335.     byte hitsLeft = ((packet_QueryReply *) Result)->TotalHits;
  336.     DWORD nextPos = 34;
  337.     QueryItem Item;
  338.  
  339.     GUID guid;
  340.     ::memset (&guid, 0, sizeof (guid));
  341.     if (hitsLeft > 0)
  342.     {
  343.         // Extract the GUID from the end of the packet for push requests
  344.         DWORD guidStart = length - 16;
  345.  
  346.         guid = * (GUID*) (Result + guidStart);
  347.     }
  348.  
  349.     while(nextPos < length - 16 && hitsLeft > 0)
  350.     {            
  351.         packet_QueryReplySet* ReplySet = (packet_QueryReplySet *) &Result[nextPos];
  352.         
  353.         Size = DWrdtoStr( makeD( flipX( ReplySet->Size)) );
  354.  
  355.         nextPos += 8;
  356.  
  357.         while( !(Result[nextPos] == NULL && Result[nextPos + 1] == NULL))
  358.             if(nextPos > length - 16)
  359.                 return;
  360.             else
  361.                 File += Result[nextPos++];
  362.         
  363.         if(Size == "0" || File == "")
  364.             return;
  365.  
  366.         if( InspectFile(File) )
  367.         {
  368.             FileType = GetIconDesc(File);
  369.  
  370.             // Add to listbox
  371.             // check if it passes subsearch
  372.             
  373.             CString lowtxt = File;
  374.             lowtxt.MakeLower();
  375.             bool fnd; // represents whether passes subsearch and sub-excludes
  376.             if (subsearchText.GetLength() == 0)
  377.                 fnd = true; // no subsearch
  378.             else
  379.                 fnd = lowtxt.Find(subsearchText) >= 0;
  380.             Item.subsearchMatch = fnd;
  381.  
  382.             // try excluding
  383.             Item.excluded = ExcludeTest(excludeText, lowtxt);
  384.  
  385.             fnd = fnd && !Item.excluded;
  386.  
  387.             if (fnd)
  388.             {
  389.                 m_lstResults.InsertItem(row, "" );
  390.                 m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Name" ), File);
  391.                 m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Bytes" ), CommaIze(Size));
  392.                 m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Type" ), FileType);
  393.                 m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Node" ), Node);
  394.                 m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Speed" ), Speed + " Kbs");
  395.                 Item.Handle = row; // invalid, BTW
  396.             }
  397.  
  398.             // Add to search results linked list
  399.             
  400.             Item.Port  = ((packet_QueryReply *) Result)->Port;
  401.             Item.Host  = ((packet_QueryReply *) Result)->Host;
  402.  
  403.             Item.Speed = makeD( flipX(((packet_QueryReply *) Result)->Speed));
  404.             Item.Index = makeD( flipX(ReplySet->Index));
  405.             Item.Size  = makeD( flipX(ReplySet->Size));
  406.             
  407.             // Remove directory information from the file name
  408.             int slash = File.ReverseFind('/');
  409.             File = File.Mid(slash + 1);
  410.  
  411.             Item.FileName = File;
  412.             Item.FileType = FileType; // Ineffiecent, replace with list in future
  413.  
  414.             Item.Guid = guid;
  415.  
  416.             // Add the icon
  417.             Item.IconIndex = GetIconIndexFromName(File);
  418.             Replies.push_back (Item);
  419.  
  420.             if(fnd && Item.IconIndex != -1)
  421.             {
  422.                 m_lstResults.SetItem(row, 0, LVIF_IMAGE, NULL, Item.IconIndex, m_lstResults.GetColumnNumber( "Name" ), 0, NULL);
  423.             }
  424.  
  425.             // Check to see if the scroll bar needs to be added
  426.             if( fnd && !NoScroll && m_lstResults.GetScrollLimit(SB_VERT))
  427.             {
  428.                 CRect rect;
  429.                 GetParentFrame()->GetClientRect(&rect);
  430.                 OnSize(SIZE_RESTORED, rect.right - 4, rect.bottom - 4);
  431.  
  432.                 NoScroll = 1;
  433.             }
  434.  
  435.             if (fnd)
  436.                 row++;
  437.             matches++;
  438.         }
  439.  
  440.         File = "";
  441.         Size = "";
  442.  
  443.         nextPos += 2;
  444.         hitsLeft--;
  445.     }
  446.  
  447.     AssignHeaderText();
  448. }
  449.  
  450. bool CViewSearch::InspectFile(CString File)
  451. {
  452.     bool Pass = 0;
  453.     File.MakeLower();
  454.  
  455.     std::vector<BlockedSearch>::iterator it;
  456.  
  457.     for( it = Doc->SearchFilter.begin(); it != Doc->SearchFilter.end(); it++)
  458.     {
  459.         if( (*it).Permis == 'A' )
  460.             if( SearchMatch( (*it).Name, File) )
  461.                 Pass = 1;
  462.  
  463.         if( (*it).Permis == 'D' )
  464.             if( SearchMatch( (*it).Name, File) )
  465.                 return 0;
  466.     }
  467.  
  468.     return Pass;
  469.     }
  470.  
  471. void CViewSearch::OnItemclickListResults(NMHDR* pNMHDR, LRESULT* pResult) 
  472. {
  473.     HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
  474.     
  475.     if(phdn->iButton == 0)
  476.     {
  477.         AfxMessageBox(m_lstResults.GetItemText(0, phdn->iItem));
  478.     }
  479.     
  480.     
  481.     *pResult = 0;
  482. }
  483.  
  484. void CViewSearch::OnClickListResults(NMHDR* pNMHDR, LRESULT* pResult) 
  485. {
  486.     m_btnDownload.EnableWindow(m_lstResults.GetFirstSelectedItemPosition() != NULL);
  487.     *pResult = 0;
  488. }
  489.  
  490. // pop up a popup menu, which right now lets one filter out a user
  491. void CViewSearch::OnRightClickListResults(NMHDR* pNMHDR, LRESULT* pResult) 
  492. {
  493.     LPNMITEMACTIVATE Control = (LPNMITEMACTIVATE) pNMHDR;
  494.  
  495.     int nItem = m_lstResults.HitTest(Control->ptAction);
  496.     if (nItem < 0 || nItem >= matches)
  497.         return;
  498.  
  499.     CMenu menu;
  500.     VERIFY(menu.LoadMenu(IDR_SRCH_RCLICK));
  501.     CMenu *pmenuPopup = menu.GetSubMenu(0);
  502.     ASSERT(pmenuPopup != NULL);
  503.  
  504.     // Display and track the popup menu
  505.     CPoint pos;
  506.     GetCursorPos(&pos);
  507.  
  508.     int res = pmenuPopup->TrackPopupMenu( (TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_NONOTIFY|TPM_RETURNCMD),
  509.                  pos.x, pos.y, this);
  510.     if (res == ID_FILTER) {
  511.         // they want to filter this user
  512.         // find out which result they clicked on
  513.         QueryItem& qry = FindQueryItemFromListIndex(nItem);
  514.         // now add the filter to our list
  515.         CIPFilter::AddFilter(CIPFilter::CIPAddress(qry.Host.a,qry.Host.b,qry.Host.c,qry.Host.d), 
  516.             CIPFilter::CFilterItem::EFilterAction(CIPFilter::CFilterItem::eFilterDeny),
  517.             true); // true here necessary
  518.         // remove all the results from this loser that are currently displayed
  519.         IP host(qry.Host);
  520.         std::list<QueryItem>::iterator it;
  521.         for (it = Replies.begin(); it != Replies.end(); )
  522.         {
  523.             if (it->Host.S_addr == host.S_addr)
  524.             {
  525.                 it = Replies.erase(it);
  526.                 continue;
  527.             }
  528.             it++;
  529.         }
  530.         // redraw
  531.         ListFromReplies();
  532.         AssignHeaderText();
  533.     }
  534.     *pResult = 0;
  535. }
  536.  
  537. void CViewSearch::OnDblclkListResults(NMHDR* pNMHDR, LRESULT* pResult) 
  538. {
  539.     LPNMITEMACTIVATE Control = (LPNMITEMACTIVATE) pNMHDR;
  540.  
  541.     int nItem = m_lstResults.HitTest(Control->ptAction);
  542.     CString Title;
  543.  
  544.     if(nItem != -1)
  545.         StartDownload(nItem);
  546.     *pResult = 0;
  547. }
  548.  
  549. void CViewSearch::OnButtonDownload() 
  550. {
  551.     int nItem;
  552.     POSITION pos = m_lstResults.GetFirstSelectedItemPosition();
  553.     
  554.     while(pos != NULL)
  555.     {
  556.         nItem = m_lstResults.GetNextSelectedItem(pos);
  557.         StartDownload(nItem);
  558.     }
  559. }
  560.  
  561. void CViewSearch::OnColumnclickListResults(NMHDR* pNMHDR, LRESULT* pResult) 
  562. {
  563.     NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  564.  
  565.     if (QueryItem::SortBy == pNMListView->iSubItem)
  566.     {
  567.         QueryItem::Reverse = !QueryItem::Reverse;
  568.     }
  569.     else
  570.     {
  571.         QueryItem::SortBy = pNMListView->iSubItem;
  572.         QueryItem::Reverse = 0;
  573.     }
  574.  
  575.     Replies.sort ();
  576.  
  577.     ListFromReplies();
  578.  
  579.     *pResult = 0;
  580. }
  581.  
  582.  
  583. void CViewSearch::OnChangeSubsearch() 
  584. {
  585.     CString s;
  586.     m_eSubsearch.GetWindowText(s);
  587.     s.MakeLower();
  588.     subsearchText = s;
  589.  
  590.     // see which replies match string
  591.     // keep track to see if we've made changes -- whether to reform list or not
  592.     bool madeAChange = false;
  593.     std::list<QueryItem>::iterator it;
  594.     for (it = Replies.begin(); it != Replies.end(); it++)
  595.     {
  596.         if (s.GetLength() == 0)
  597.         {
  598.             if (!it->subsearchMatch)
  599.             {
  600.                 madeAChange = true;
  601.                 it->subsearchMatch = true;
  602.             }
  603.             continue;
  604.         }
  605.         CString lo = it->FileName;
  606.         lo.MakeLower();
  607.         bool oldMatch = it->subsearchMatch;
  608.         bool fnd = SearchMatch("*" + s + "*", lo);
  609.         it->subsearchMatch = fnd;
  610.         if (it->subsearchMatch != oldMatch)
  611.             madeAChange = true;
  612.     }
  613.  
  614.     if (madeAChange)
  615.     {
  616.         Replies.sort();
  617.         ListFromReplies();
  618.         AssignHeaderText();
  619.     }
  620. }
  621.  
  622. // Test name against comma delimited excludes, return true if one matches
  623. bool CViewSearch::ExcludeTest(CString exclude, CString name)
  624. {
  625.     if (exclude.GetLength() == 0)
  626.         return false;
  627.  
  628.     name.MakeLower();
  629.     exclude.MakeLower();
  630.     // parse exclude out
  631.  
  632.     CString strSub;
  633.     int iToken = 0;
  634.     
  635.     while(AfxExtractSubString(strSub, exclude, iToken, ','))
  636.     {
  637.         iToken++;
  638.         if(SearchMatch("*" + strSub + "*", name))
  639.         {
  640.             return true;
  641.         }
  642.     }
  643.  
  644.     return false;
  645. }
  646.  
  647. void CViewSearch::OnChangeExclude() 
  648. {
  649.     CString s;
  650.     m_eExclude.GetWindowText(s);
  651.     s.MakeLower();
  652.     excludeText = s;
  653.  
  654.     // see which replies match exclude string -- they're invalid
  655.     // keep track to see if we've made changes -- whether to reform list or not
  656.     bool madeAChange = false;
  657.     std::list<QueryItem>::iterator it;
  658.     for (it = Replies.begin(); it != Replies.end(); it++)
  659.     {
  660.         if (s.GetLength() == 0)
  661.         {
  662.             if (it->excluded)
  663.             {
  664.                 madeAChange = true;
  665.                 it->excluded = false;
  666.             }
  667.             continue;
  668.         }
  669.         bool match = ExcludeTest(s, it->FileName);
  670.         bool oldMatch = it->excluded;
  671.         it->excluded = match;
  672.         if (match != oldMatch)
  673.             madeAChange = true;
  674.     }
  675.  
  676.     if (madeAChange)
  677.     {
  678.         Replies.sort();
  679.         ListFromReplies();
  680.         AssignHeaderText();
  681.     }
  682. }
  683.  
  684. /*
  685. take our reply list and create the elements of the listcontrol from it
  686. also count rows, as we might have just done some subsearch
  687. */
  688. void CViewSearch::ListFromReplies()
  689. {
  690.  
  691.     m_lstResults.SetRedraw (FALSE);
  692.     m_lstResults.DeleteAllItems();
  693.  
  694.     std::list<QueryItem>::iterator it;
  695.  
  696.     row = 0;
  697.  
  698.     for (it = Replies.begin(); it != Replies.end(); it++)
  699.     {
  700.         if (!it->subsearchMatch || it->excluded)
  701.             continue;
  702.  
  703.         // Add to listbox
  704.         m_lstResults.InsertItem(row, "");
  705.         m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Name" ), (*it).FileName);
  706.         m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Bytes" ), CommaIze(DWrdtoStr((*it).Size)));
  707.         m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Type" ), (*it).FileType);
  708.         m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Node" ), IPtoStr((*it).Host));
  709.         m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Speed" ), DWrdtoStr((*it).Speed) + " Kbs");
  710.  
  711.         if ((*it).IconIndex != -1)
  712.         {
  713.             m_lstResults.SetItem(row, 0, LVIF_IMAGE, NULL, (*it).IconIndex, m_lstResults.GetColumnNumber( "Name" ), 0, NULL);
  714.         }
  715.  
  716.         row++;
  717.     }
  718.  
  719.     m_lstResults.SetRedraw();
  720. }
  721.  
  722. // set the header text -- how many matches so far
  723. void CViewSearch::AssignHeaderText()
  724. {
  725.     CString Title = WrdtoStr(matches);
  726.     Title += " Matches";
  727.     // maybe there's a subsearch -- if so, add text
  728.     if (matches != row)
  729.         Title += " (" + WrdtoStr(row) + " shown)";
  730.     m_stcMatches.SetWindowText(Title);
  731. }
  732.  
  733. QueryItem& CViewSearch::FindQueryItemFromListIndex(int nItem)
  734. {
  735.     ASSERT (nItem >= 0);
  736.     ASSERT (nItem < Replies.size ());
  737.     
  738.     std::list <QueryItem>::iterator it;
  739.  
  740.     it = Replies.begin();
  741.     // find the associated reply
  742.     while ( (it != Replies.end()) && (!it->subsearchMatch || it->excluded) )
  743.         it++;
  744.     for (int loop = 0; loop < nItem && (it != Replies.end()); ++loop)
  745.     {
  746.         do {
  747.             it++;
  748.         } while ( (it != Replies.end()) && (!it->subsearchMatch || it->excluded) );
  749.     }
  750.  
  751.     ASSERT (it != Replies.end ());
  752.  
  753.     return *it;
  754. }
  755.  
  756. void CViewSearch::StartDownload(int nItem)
  757. {
  758.     
  759.     ((CGnucleusApp *) AfxGetApp())->TransferFrame->ShowWindow(SW_SHOW);
  760.     ((CGnucleusApp *) AfxGetApp())->TransferFrame->BringWindowToTop();
  761.     
  762.     QueryItem& qry = FindQueryItemFromListIndex(nItem);
  763.  
  764.     int b_is_dest_private_ip = CIPFilter::IsPrivateIP( qry.Host, StrtoIP(Comm->localHost) );
  765.  
  766.     if( b_is_dest_private_ip == 0x2)
  767.         Comm->NewPushRequest(qry);            // the remote download is not on the local subnet, push is the only way
  768.     else if( b_is_dest_private_ip == 0x4)
  769.         return;                                // we are on a different private IP address space.  There is no way of download.
  770.                                             // TODO: generate an error message
  771.     else
  772.         // the destination is either on an open IP space, or it might be on our local address space, if not a push is generated.
  773.         ((CViewTransfer *) ((CGnucleusApp *) AfxGetApp())->TransferFrame->GetActiveView())->NewDownload(qry);
  774.  
  775. }
  776.